{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "import glob\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import json\n",
    "\n",
    "import tensorflow as tf\n",
    "\n",
    "import lucid.modelzoo.vision_models as models\n",
    "from lucid.misc.io import show\n",
    "import lucid.optvis.objectives as objectives\n",
    "import lucid.optvis.param as param\n",
    "import lucid.optvis.render as render\n",
    "import lucid.optvis.transform as transform\n",
    "from keras.preprocessing import image\n",
    "from keras.applications.inception_v3 import preprocess_input\n",
    "import tqdm\n",
    "\n",
    "from scipy.stats import mode\n",
    "import scipy.misc\n",
    "import matplotlib.ticker as plticker\n",
    "\n",
    "import seaborn as sns\n",
    "\n",
    "from PIL import Image\n",
    "\n",
    "import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "googlenet = models.InceptionV1()\n",
    "googlenet.load_graphdef()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Layer (belonging to InceptionV1) <conv2d0: 64> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <conv2d1: 64> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <conv2d2: 192> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed3a: 256> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed3b: 480> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed4a: 508> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed4b: 512> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed4c: 512> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed4d: 528> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed4e: 832> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed5a: 832> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <mixed5b: 1024> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <head0_bottleneck: 128> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <nn0: 1024> ([{'dense'}]),\n",
       " Layer (belonging to InceptionV1) <softmax0: 1008> ([{'dense'}]),\n",
       " Layer (belonging to InceptionV1) <head1_bottleneck: 128> ([{'conv'}]),\n",
       " Layer (belonging to InceptionV1) <nn1: 1024> ([{'dense'}]),\n",
       " Layer (belonging to InceptionV1) <softmax1: 1008> ([{'dense'}]),\n",
       " Layer (belonging to InceptionV1) <softmax2: 1008> ([{'dense'}])]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "googlenet.layers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "layers = {\n",
    "    'mixed3a': 256,\n",
    "    'mixed3b': 480,\n",
    "    'mixed4a': 508,\n",
    "    'mixed4b': 512,\n",
    "    'mixed4c': 512,\n",
    "    'mixed4d': 528,\n",
    "    'mixed4e': 832,\n",
    "    'mixed5a': 832,\n",
    "    'mixed5b': 1024\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_of_classes = 1000\n",
    "prob_mass_threshold = 0.01\n",
    "batch = 200"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "def _parse_function(example_proto, image_size=224):\n",
    "    def _bytes_feature(value):\n",
    "        return tf.train.Feature(\n",
    "            bytes_list=tf.train.BytesList(value=[value]))\n",
    "\n",
    "    def _int64_feature(value):\n",
    "        return tf.train.Feature(\n",
    "            int64_list=tf.train.Int64List(value=[value]))\n",
    "    \n",
    "    feature_set = {\n",
    "        'image/filename': tf.FixedLenFeature([], tf.string),\n",
    "        'image/encoded': tf.FixedLenFeature([], tf.string),\n",
    "        'image/height': tf.FixedLenFeature([], tf.int64),\n",
    "        'image/width': tf.FixedLenFeature([], tf.int64),\n",
    "        'image/channels': tf.FixedLenFeature([], tf.int64),\n",
    "        'image/class/label': tf.FixedLenFeature([], tf.int64),\n",
    "        'image/class/synset': tf.FixedLenFeature([], tf.string)}\n",
    "  \n",
    "    parsed_features = tf.parse_single_example(example_proto, feature_set)\n",
    "    \n",
    "    image_id = parsed_features['image/filename']\n",
    "    \n",
    "    label = parsed_features['image/class/label']\n",
    "    \n",
    "    width = parsed_features['image/width']\n",
    "    height = parsed_features['image/height']\n",
    "    channels = parsed_features['image/channels']\n",
    "    \n",
    "    synset = parsed_features['image/class/synset']\n",
    "    \n",
    "    image = parsed_features['image/encoded']\n",
    "    image = tf.image.decode_jpeg(image, channels=3)\n",
    "    image = tf.image.resize_images(image, tf.constant([image_size, image_size]))\n",
    "    \n",
    "    return image, label, synset\n",
    "\n",
    "\n",
    "filenames = glob.glob('/media/fred/lime/imagenet-tf-records/*') \n",
    "\n",
    "# print(len(filenames))\n",
    "\n",
    "for layer in layers:\n",
    "    print(layer)\n",
    "\n",
    "    num_of_chanels_in_layer = layers[layer]\n",
    "\n",
    "    A = np.zeros([num_of_classes, num_of_chanels_in_layer], dtype=int)\n",
    "\n",
    "    with tf.Graph().as_default():\n",
    "        dataset = tf.data.TFRecordDataset(filenames)\n",
    "        dataset = dataset.map(_parse_function)\n",
    "        dataset = dataset.map(lambda img, lab, syn: (preprocess_input(img), lab, syn))\n",
    "        dataset = dataset.batch(batch)\n",
    "\n",
    "        iterator = dataset.make_one_shot_iterator()\n",
    "        t_preprocessed_images, t_labels, t_synsets = iterator.get_next()\n",
    "\n",
    "        T = render.import_model(googlenet, t_preprocessed_images, None)\n",
    "        t_imgs_acts = T(layer)\n",
    "        t_imgs_acts_max = tf.math.reduce_max(t_imgs_acts, axis=[1,2])\n",
    "\n",
    "        progress_counter = 0\n",
    "        with tf.Session() as sess:\n",
    "            start = time.time()\n",
    "\n",
    "            try:\n",
    "                with tqdm.tqdm(total=1281167, unit='imgs') as pbar:\n",
    "                    while(True):\n",
    "                        progress_counter += 1\n",
    "                        imgs_acts_max, labels, synsets = sess.run([t_imgs_acts_max, t_labels, t_synsets])\n",
    "\n",
    "                        # no sess.run after this\n",
    "                        # python code here on out\n",
    "                        for i in range(imgs_acts_max.shape[0]):\n",
    "\n",
    "                            # remove outlier / non-semantic channels\n",
    "                            if layer == 'mixed3a':\n",
    "                                imgs_acts_max[i][67] = 0\n",
    "                                imgs_acts_max[i][190] = 0\n",
    "\n",
    "                            if layer == 'mixed3b':\n",
    "                                imgs_acts_max[i][390] = 0\n",
    "                                imgs_acts_max[i][399] = 0\n",
    "                                imgs_acts_max[i][412] = 0\n",
    "\n",
    "                            # METHOD 2: prob mass\n",
    "                            top_channels = []\n",
    "                            working_acts_max = imgs_acts_max[i]/np.sum(imgs_acts_max[i])\n",
    "                            prob_mass = 0\n",
    "                            sorted_working_acts_max, sorted_inds = (list(t) for t in zip(*sorted(zip(working_acts_max, list(range(working_acts_max.shape[0]))), reverse=True)))\n",
    "                            k = 0\n",
    "                            while prob_mass < prob_mass_threshold:\n",
    "                                top_channels.append(sorted_inds[k])\n",
    "                                prob_mass += sorted_working_acts_max[k]\n",
    "                                k += 1\n",
    "                            for top_channel in top_channels:\n",
    "                                A[labels[i]-1][top_channel] += 1\n",
    "                            # print(synsets[i], labels[i])\n",
    "\n",
    "                        pbar.update(len(labels))\n",
    "\n",
    "            except tf.errors.OutOfRangeError:\n",
    "                pass\n",
    "\n",
    "            end = time.time()\n",
    "            print(end - start)\n",
    "            print(progress_counter)\n",
    "            print(progress_counter*batch)\n",
    "\n",
    "    np.savetxt('data/A-matrices/' + 'A-' + str(prob_mass_threshold) + '-' + layer + '.csv', A, delimiter=',', fmt='%i')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# plt.figure(figsize=(16,16))\n",
    "# plt.imshow(A)\n",
    "# plt.colorbar()\n",
    "# plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (tensorflow)",
   "language": "python",
   "name": "tensorflow"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
